# -*- coding: utf8

import mailbox
import lxml.html
from lxml.html.clean import Cleaner
import os
from email.Header import decode_header
from email.utils import parseaddr

from django.conf import settings
from django.utils.encoding import force_unicode
from mitems.models import Item_category, Item, UserProfile, ItemImage, Airtime
from mitems.tools.logs import Log
from mitems.tools.utils import make_upload_path
from facegraph import Graph


log = Log(settings.MAIL_LOG_FILE, settings.MAIL_LOG_LOGGER,
          settings.MAIL_LOG_SIZE,settings.MAIL_LOG_COUNT, settings.DEBUG)

AIRTIME_USERS = list(UserProfile.objects.filter(is_superuser=True)) \
                or list(UserProfile.objects.filter(is_bot=True))
AIRTIME_USER = AIRTIME_USERS[0] if AIRTIME_USERS else None


def resize_image(content, filename):
    filename_small = os.path.join(settings.MEDIA_ROOT, make_upload_path(None, None))
    filename_big = os.path.join(settings.MEDIA_ROOT, make_upload_path(None, None))
    try:
        with open(filename_small, 'wb+') as destination:
            destination.write(content)
        with open(filename_big, 'wb+') as destination:
            destination.write(content)
    except IOError:
        return {'error':  'Cannot save image: %s' % filename }
    return {'small': os.path.basename(filename_small),
            'big': os.path.basename(filename_big)}


def decode_subject(header):
    """Decode mail headers"""
    if not header:
        return None
    heads = []
    for head, encoding in decode_header(header):
        try:
            add_head = head.decode(encoding) if encoding else head.decode()
        except (LookupError, UnicodeDecodeError):
            add_head = head.decode('utf-8', 'ignore')
        heads.append(add_head)
    return ''.join(heads)[:256].replace('\n', '')


def remove_tags(html):
    """Clean html letter"""
    cleaner = Cleaner(style=True)
    return cleaner.clean_html(lxml.html.fromstring(html)).text_content()


def mark_as_read(mdr, message, key):
    message.set_subdir('cur')
    message.add_flag('S')
    mdr.add(message)
    mdr.discard(key)
    mdr.flush()


def read_message_body(body):
    result = {}
    body_list = [ i.strip() for i in body.split('\n') if i.split()]
    if not len(body_list):
        return result
    cat = body_list[-1].strip()
    if cat[0] == '#':
        try:
            category = Item_category.objects.get(category=cat[1:].lower())
            result['category'] = category
            description = ' '.join(body_list[:-1])
        except Item_category.DoesNotExist:
            description = ' '.join(body_list)
    else:
        description = ' '.join(body_list)
    if description:
        result['description'] = description[:256]
    return result


def read_message(message):
    body, content, filename = None, None, None
    image = False
    for data in message.walk():
        if not data.is_multipart():
            maintype = data.get_content_maintype()
            subtype = data.get_content_subtype()
            charset = message.get_content_charset() or 'utf-8'
            if maintype == 'text':
                if subtype == 'html':
                    body = remove_tags(data.get_payload(decode=1))
                else:
                    body = data.get_payload(decode=1).decode(charset, 'ignore')
            elif maintype == 'image' and subtype in ('jpeg', 'png', 'gif'):
                image = True
                content = data.get_payload(decode=1)
                filename = data.get_filename()
                image_size = len(content)
                if image_size > settings.MAIL_MAX_ATTACH:
                    error = ('image size of %s file is more than %s: %.02f' %
                             (filename, settings.MAIL_MAX_ATTACH, (image_size/1024.0/1024)))
                    return {'error': error }
            else:
                filename = data.get_filename()
                return {'error': ('%s is not image: %s/%s' % (filename, maintype, subtype))}
    return dict(body=body, image={'content': content, 'filename': filename} if image  else {})


def read_mailbox(directory):
    mdr = mailbox.Maildir(directory, mailbox.MaildirMessage)
    for key in mdr.keys():
        message = mdr.get_message(key)
        if not 'S' in message.get_flags():
            item = {}
            subject =  decode_subject(message['Subject'])
            if not subject or not subject.split():
                mdr.discard(key)
                log.log('No subject: %s' % message['To'], 'error')
                continue
            recipient = parseaddr(message['To'])[-1]
            try:
                created_by = UserProfile.objects.get(mobile_email=recipient)
            except UserProfile.DoesNotExist:
                mdr.discard(key)
                log.log('User with %s mobile email does not exist' % recipient, 'error')
                continue
            message_result = read_message(message)
            error = message_result.get('error')
            if error:
                mdr.discard(key)
                log.log(error, 'error')
                continue
            item.update(dict(message=subject, created_by=created_by,
                             updated_by=created_by, location=created_by.location, is_mail=True))
            body = message_result.get('body')
            if body:
                item.update(read_message_body(body))
            image = message_result.get('image')
            if image:
                image_files = resize_image(image['content'], image['filename'])
                error = image_files.get('error')
                if error:
                    log.log(error, 'error')
                    continue
                item.update(image_files)
            saved_item = save_item(item)
            if saved_item:
                mark_as_read(mdr, message, key)
                log.log('%s\'s item has been saved. subject: %s'
                        % (created_by, subject), 'info')
            else:
                mdr.discard(key)


def save_item(item_dict):
    try:
        small_image = item_dict.pop('small', None)
        big_image = item_dict.pop('big', None)
        item = Item.objects.create(**item_dict)
        if small_image:
            ItemImage.objects.create(item=item, image=small_image, size='small')
        if big_image:
            ItemImage.objects.create(item=item, image=big_image, size='big')
        if AIRTIME_USER:
            Airtime(user=AIRTIME_USER, item=item, count=settings.MAIL_AIRTIME_COUNT).save()
        if item.created_by.fb_auto_post and 'facebook' in item.created_by.get_auth_providers():
            try:
                access_token = item.created_by.get_facebook_token()
                picture = item.get_small_image() or ''
                if picture:
                    picture = picture.get_absolute_url()
                if access_token:
                    graph = Graph(access_token)
                    graph.me.feed.post(
                        message='',
                        picture=picture,
                        link=item.get_short_url(),
                        name=force_unicode(item.message),
                        description=settings.FACEBOOK_MESSAGE
                    )
            except Exception as err:
                log.log('Error facebook share: %s' % err, 'error')
        return item
    except Exception as error:
        log.log('Cannot create item: %s' % error, 'error')
        return False

def directory_list():
    mail_dir = getattr(settings, 'MAIL_DIR', None)
    return [os.path.join(mail_dir, cur_dir) for cur_dir in os.listdir(mail_dir)] if mail_dir else []